/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @file  SpiSlave_Driver.c
 * @brief Semidrive. AUTOSAR 4.3.1 MCAL SpiSlave_Slave plugins.
 */

#ifdef __cplusplus
extern "C" {
#endif

/*******************************************************************************
**                      Include Section                                       **
*******************************************************************************/
#include "SpiSlave.h"
#include "SpiSlave_reg.h"
#include "SpiSlave_Irq.h"
#include "SpiSlave_Ip.h"
#include "SpiSlave_Mld.h"
#include "SchM_SpiSlave.h"
#include "SpiSlave_Fault.h"
#include "SpiSlave_PbCfg.h"
#include "SpiSlave_Driver.h"
/*PRQA S 2877 EOF*/

/*****************************************************************************************
 *                                  Private Variable Definitions                         *
 ****************************************************************************************/
/** \brief  core 0 driver handler data  */
#define SPI_SLV_CORE0_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "SpiSlave_MemMap.h"
#if SPI_SLV_CFG_ENABLE_CORE0 == STD_ON
static  struct SpiSlave_Driver_Handler SpiSlaveHandler_Core0 LOCATE_ALIGNED(CACHE_LINE);
#endif
#define SPI_SLV_CORE0_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "SpiSlave_MemMap.h"
/** \brief  core 1 driver handler data  */
#define SPI_SLV_CORE1_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "SpiSlave_MemMap.h"
#if SPI_SLV_CFG_ENABLE_CORE1 == STD_ON
static  struct SpiSlave_Driver_Handler  SpiSlaveHandler_Core1 LOCATE_ALIGNED(CACHE_LINE);
#endif
#define SPI_SLV_CORE1_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "SpiSlave_MemMap.h"
/** \brief  core 2 driver handler data  */
#define SPI_SLV_CORE2_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "SpiSlave_MemMap.h"
#if SPI_SLV_CFG_ENABLE_CORE2 == STD_ON
static  struct SpiSlave_Driver_Handler  SpiSlaveHandler_Core2 LOCATE_ALIGNED(CACHE_LINE);
#endif
#define SPI_SLV_CORE2_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "SpiSlave_MemMap.h"
/** \brief  core 3 driver handler data  */
#define SPI_SLV_CORE3_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "SpiSlave_MemMap.h"
#if SPI_SLV_CFG_ENABLE_CORE3 == STD_ON
static  struct SpiSlave_Driver_Handler  SpiSlaveHandler_Core3 LOCATE_ALIGNED(CACHE_LINE);
#endif
#define SPI_SLV_CORE3_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "SpiSlave_MemMap.h"
/** \brief  core 4 driver handler data  */
#define SPI_SLV_CORE4_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "SpiSlave_MemMap.h"
#if SPI_SLV_CFG_ENABLE_CORE4 == STD_ON
static  struct SpiSlave_Driver_Handler  SpiSlaveHandler_Core4 LOCATE_ALIGNED(CACHE_LINE);
#endif
#define SPI_SLV_CORE4_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "SpiSlave_MemMap.h"

#define SPI_SLV_START_SEC_CONST_UNSPECIFIED
#include "SpiSlave_MemMap.h"
/******************************************************************************************
 *                     Global Variable Declarations
 *****************************************************************************************/
 /** \brief  This is the core spi driver handler global variable object */
struct SpiSlave_Driver_Handler *const SpiSlaveHandler[SPI_SLV_CFG_CORES] =
{
#if SPI_SLV_CFG_ENABLE_CORE0 == STD_ON
    &SpiSlaveHandler_Core0,
#else
    NULL_PTR,
#endif
#if SPI_SLV_CFG_CORES > 1U
#if SPI_SLV_CFG_ENABLE_CORE1 == STD_ON
    &SpiSlaveHandler_Core1,
#else
    NULL_PTR,
#endif
#endif
#if SPI_SLV_CFG_CORES > 2U
#if SPI_SLV_CFG_ENABLE_CORE2 == STD_ON
    &SpiSlaveHandler_Core2,
#else
    NULL_PTR,
#endif
#endif
#if SPI_SLV_CFG_CORES > 3U
#if SPI_SLV_CFG_ENABLE_CORE3 == STD_ON
    &SpiSlaveHandler_Core3,
#else
    NULL_PTR,
#endif
#endif
#if SPI_SLV_CFG_CORES > 4U
#if SPI_SLV_CFG_ENABLE_CORE4 == STD_ON
    &SpiSlaveHandler_Core4
#else
    NULL_PTR,
#endif
#endif
};
#define SPI_SLV_STOP_SEC_CONST_UNSPECIFIED
#include "SpiSlave_MemMap.h"
/*******************************************************************************
**                    Static Function Definitions                             **
*******************************************************************************/
#define SPI_SLV_START_SEC_CODE_FAST
#include "SpiSlave_MemMap.h"

/**
 * @brief Get SPI Slave Core ID
 *
 *  Retrieves the core ID of the current CPU by calling the Mcal_GetCpuIndex function
 *   and handles it accordingly based on the configuration parameters SPI_SLV_SINGLE_CORE_HANDLER and SPI_SLV_DEV_ERROR_DETECT.
 *
 * @return  Returns the core ID or a fixed value of 0 depending on the value of the
 *   configuration parameter SPI_SLV_SINGLE_CORE_HANDLER.
 */
uint8 SpiSlave_GetCoreID(void)
{
#if (SPI_SLV_SINGLE_CORE_HANDLER == STD_OFF)
    return Mcal_GetCpuIndex();
#else
#if (SPI_SLV_DEV_ERROR_DETECT == STD_ON)
    if(Mcal_GetCpuIndex() != (uint8)SPI_SLV_SINGLE_CORE_ID)
    {
        Det_ReportRuntimeError(SPI_SLV_MODULE_ID, SPI_SLV_INSTANCE_ID, 0x11, SPI_SLV_E_ILLEGAL_RES);
    }
#endif /*SPI_SLV_DEV_ERROR_DETECT == ON */
    return SPI_SLV_SINGLE_CORE_ID;
#endif
}

#define SPI_SLV_STOP_SEC_CODE_FAST
#include "SpiSlave_MemMap.h"

#define SPI_SLV_START_SEC_CODE
#include "SpiSlave_MemMap.h"

/**
 * @brief Get SPI Slave Hardware Unit Configuration.
 *
 * Retrieves the configuration information of the SPI slave hardware unit corresponding to
 *    the given hardware unit ID and returns a pointer to the configuration.
 *
 * @param HwUnitId The hardware unit ID
 *
 * @return Pointer to the SPI slave hardware unit configuration, returns NULL_PTR if not found.
 */
static inline const SpiSlave_HwUnitConfigType *Get_JobHwUnitConfig(uint8 HwUnitId)
{
    for (uint8 Idx = 0; Idx < SPI_SLV_TOTAL_HW_COUNT; Idx++) {
        /* spi HW units init */
        if (HwUnitId == SpiSlave_HwUnitConfig[Idx].HwUnit) {
            return &SpiSlave_HwUnitConfig[Idx];
        }
    }

    return NULL_PTR;
}
/**
 * @brief Get Slave Mode Configuration Device Index.
 *
 *  Retrieves the corresponding device index from the SPI slave task configuration
 *  based on the given hardware unit ID.
 *
 * @param HwUnitId The hardware unit ID
 *
 * @return The corresponding device index, returns 0 if not found.
 */
static uint8 Get_SlaveModeConfigDeviceIdx(uint8 HwUnitId)
{
    const SpiSlave_JobCfgType *PtrJobCfg = SpiSlave_JobConfig;

    for (uint8 JobIdx = 0; JobIdx < SPI_SLV_TOTAL_JOB_COUNT; JobIdx++) {
        /* spi HW units init */
        if (HwUnitId == PtrJobCfg[JobIdx].HWUnit) {
            if (PtrJobCfg[JobIdx].DeviceIdx < SPI_SLV_TOTAL_DEV_COUNT) {
                return PtrJobCfg[JobIdx].DeviceIdx;
            }
        }
    }

    return 0;
}

/**
 * @description:  check the channel has configrated.
 * @param {SpiSlave_SequenceType} Sequence
 * @return {*}
 */
static boolean SpiSlave_ChannelStatusIsOk(SpiSlave_SequenceType Sequence)
{
    uint8 CoreId = SpiSlave_GetCoreID();
    struct SpiSlave_Driver_Handler *PerCoreHandler = SpiSlaveHandler[CoreId];
    SpiSlave_JobType jobId = SpiSlave_SequenceConfig[Sequence].JobList[0];
    SpiSlave_ChannelType channelId = SpiSlave_JobConfig[jobId].ChannelList[0];
    if(B_SLV_NO_SETED == PerCoreHandler->SpiSlave_SpiChannelState[channelId].BuffSta)
    {
        return FALSE;
    }
    return TRUE;
}
/** **************************************************************************************
 * \brief
 *
 * \verbatim
 * Syntax             : static void SpiSlave_BusPrivInit(uint8 BusIdx)
 *
 * Service ID[hex]    : 0x00
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : configPtr - Pointer to configuration set
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Init Bus Priv Data init.
 * \endverbatim
 * Traceability       :
 *****************************************************************************************/
static void SpiSlave_BusPrivInit(uint8 BusIdx)
{
    uint8 CoreId = SpiSlave_GetCoreID();
    struct SpiSlave_Driver_Handler *PerCoreHandler = SpiSlaveHandler[CoreId];
    PerCoreHandler->SpiBus[BusIdx].Bus_Priv.flags = 0;
#if (SPI_SLV_ENABLE_DMA == STD_ON)
    /* BusIdx is not config order */
    const SpiSlave_HwUnitConfigType *HwUnitConfigPtr =  Get_JobHwUnitConfig(BusIdx);
#endif

#if (SPI_SLV_ENABLE_DMA == STD_ON)

    if (HwUnitConfigPtr != NULL_PTR && HwUnitConfigPtr->HwDMA == TRUE) {
        PerCoreHandler->SpiBus[BusIdx].Bus_Priv.flags |= SPI_SLV_DMA_TX_ENABLE | SPI_SLV_DMA_RX_ENABLE;
    }

#endif
#if (SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_1)
    PerCoreHandler->SpiBus[BusIdx].Bus_Priv.flags |= SPI_SLAVE_INTERRUPT_MODE;
#endif
    PerCoreHandler->SpiBus[BusIdx].Bus_Priv.dma_ch_rx = NULL_PTR;
    PerCoreHandler->SpiBus[BusIdx].Bus_Priv.dma_ch_tx = NULL_PTR;
    PerCoreHandler->SpiBus[BusIdx].Bus_Priv.dma_err = 0;
}
/** **************************************************************************************
 * \brief This function Init Device Priv Data init..
 *
 * \verbatim
 * Syntax             : void SpiSlave_DevicePrivInit(uint8 DevIdx,
 *                       const SpiSlave_JobCfgType *JobType)
 *
 * Service ID[hex]    : 0x00
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : configPtr - Pointer to configuration set
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Resume the spi handler to active.
 * \endverbatim
 * Traceability       :
 *****************************************************************************************/
static void SpiSlave_DevicePrivInit(uint8 DevIdx, const SpiSlave_JobCfgType *JobType)
{
    SpiSlave_clock_mode mode;
    uint8 CoreId = SpiSlave_GetCoreID();
    struct SpiSlave_Driver_Handler *PerCoreHandler = SpiSlaveHandler[CoreId];

    /* update clock phase and polarity */
    if (JobType->ShiftClk == SPI_SLV_HIGH) {
        /* CPOL = 1*/
        if (JobType->ShiftEdge == SPI_SLV_TRAILING) {
            /* CPOA = 0 mode = 2*/
            mode = SPI_SLV_SCPO1_SCPH0;
        } else {
            /* CPOA = 1 mode = 3*/
            mode = SPI_SLV_SCPO1_SCPH1;
        }
    } else {
        /* CPOL = 0 */
        if (JobType->ShiftEdge == SPI_SLV_TRAILING) {
            /* CPOA = 0 mode = 0*/
            mode = SPI_SLV_SCPO0_SCPH0;
        } else {
            /* CPOA = 1 mode = 1*/
            mode = SPI_SLV_SCPO0_SCPH1;
        }
    }
    PerCoreHandler->SpiDevice[DevIdx].Device_Priv.flags = 0;
    PerCoreHandler->SpiDevice[DevIdx].Device_Priv.mode = (enum spi_slv_tim_mode)(mode);

    PerCoreHandler->SpiDevice[DevIdx].Device_Priv.nss_idx  = JobType->CSPin;
    PerCoreHandler->SpiDevice[DevIdx].Device_Priv.width = JobType->DataWidth;
    SpiSLvFaultInj_SpiSLv_Paritychk();
    PerCoreHandler->SpiDevice[DevIdx].Device_Priv.parity = (uint8)JobType->parityType;
    SpiSLvFaultInj_SpiSLv_baudratechk();
    PerCoreHandler->SpiDevice[DevIdx].Device_Priv.baudratechk =
                        FV_SPI_SCK_CHK_UPPER_LIMIT(JobType->SpiBaudRateCheckMax);
    PerCoreHandler->SpiDevice[DevIdx].Device_Priv.baudratechk |=
                        FV_SPI_SCK_CHK_LOWER_LIMIT(JobType->SpiBaudRateCheckMin);

    if (JobType->BitOrder == SPI_SLV_LSB)
    {
        PerCoreHandler->SpiDevice[DevIdx].Device_Priv.flags |= F_SLV_DEV_LSB;
    }

    if (JobType->CSPolarity == (uint8)SPI_SLV_HIGH)
    {
        PerCoreHandler->SpiDevice[DevIdx].Device_Priv.flags |= F_SLV_DEV_NSS_HIGH;
    }
    if (TRUE == JobType->IsLe2Be)
    {
        PerCoreHandler->SpiDevice[DevIdx].Device_Priv.flags |= F_SLV_DEV_IS_BE;
    }
    if(SPI_SLV_P_NONE != JobType->parityType)
    {
        PerCoreHandler->SpiDevice[DevIdx].Device_Priv.flags |= F_SLV_DEV_PARITY_CHK;
    }

    if (JobType->SpiBaudRateCheckMax || JobType->SpiBaudRateCheckMin)
    {
        PerCoreHandler->SpiDevice[DevIdx].Device_Priv.flags |= F_SLV_DEV_BAUDRATE_CHK;
    }
    SpiSLvFaultInj_SpiSLv_timeoutchk();
    if(0u != JobType->Transtimout)
    {
        PerCoreHandler->SpiDevice[DevIdx].Device_Priv.flags |= F_SLV_DEV_TIMEOUT_CHK;
    }
    PerCoreHandler->SpiDevice[DevIdx].Device_Priv.timeout = JobType->Transtimout;

}
#if ((SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_1) || (SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_2))
#if defined(SPI_SLV_DEBUG_LOG)
/**
 * @brief Display SPI Slave Sequence Node Information.
 *
 * Prints the given SPI slave sequence node information to the debug output.
 *
 * @param Node Node Pointer to the SPI slave sequence node.
 */
void Show_SeqNode(struct SpiSlave_SeqNode *Node)
{
    SPI_SLV_DBG("---------------------------------------------------------\n");
    SPI_SLV_DBG("seq @%p sid:%d Pri:%d Int:%d Cur:%p ,CurJId:%d ",
            Node, Node->SeqId, Node->Priorty, Node->Interruptable,Node->CurJob);
    if(Node->CurJob)
      SPI_SLV_DBG("seq @%p CurJId:%d ",Node->CurJob->JobId);

    if(Node->Node.Next)
      SPI_SLV_DBG("seq @%p Next:%p ",Node,SpiSlaveGetSeqNode(Node->Node.Next));

    if(Node->Node.Prev)
      SPI_SLV_DBG("seq @%p Prev:%p ",Node,SpiSlaveGetSeqNode(Node->Node.Prev));
    SPI_SLV_DBG("\n");

    SPI_SLV_DBG("---------------------------------------------------------\n");
}

/**
 * @brief Display All Sequence Nodes
 *
 * This function is used to display information about all sequence nodes.
 *
 */
void Show_AllSeqNode(void)
{
    uint8 CoreId = SpiSlave_GetCoreID();
    struct SpiSlave_Driver_Handler *PerCoreHandler = SpiSlaveHandler[CoreId];
    struct SpiSlave_SeqNode *SeqNode = PerCoreHandler->SeqNode;

    for (uint16 Seqid = 0; Seqid < SPI_SLV_TOTAL_SEQ_COUNT; Seqid++) {
        Show_SeqNode(&SeqNode[Seqid]);
    }
}

/**
 * @brief Display SPI Slave Scheduler Information
 *
 * This function is used to display relevant information about the SPI slave scheduler,
 * including its status, next node, previous node, hardware status mask,
 * pending sequence count, and so on.
 *
 * @param Sche Pointer to the SPI slave scheduler
 */
void Show_scheduler(struct SpiSlave_Scheduler *Sche)
{
    struct SpiSlave_SeqNode *Node;
    struct SpiSlave_list *ListNode;
    SPI_SLV_DBG("Sche Sta:%d Next:%p Prev:%p HwMask:%02x pendc:%d\n",
            Sche->State,
            SpiSlaveGetSeqNode(Sche->SeqQueue.Next),
            SpiSlaveGetSeqNode(Sche->SeqQueue.Prev),
            Sche->HwStatusMask,
            Sche->PendingSeqCnt
           );

    ListNode = Sche->SeqQueue.Next;

    for (uint8 i = 0; i < SPI_SLV_TOTAL_HW_COUNT; i++)
        SPI_SLV_DBG("Hw %d: %p \n", i, Sche->JobCurr[i]);

    while (ListNode && ListNode != &Sche->SeqQueue) {
        Node = SpiSlaveGetSeqNode(ListNode);
        Show_SeqNode(Node);
        ListNode = Node->Node.Next;
    }
}

/**
 * @brief Display Task Node
 *
 * This function is used to display information about a
 *   task node in the SPI slave device driver.
 *
 * @note This function does not return a value.
 */
void Show_JobNode(void)
{
    struct SpiSlave_JobNode *JNode;
    uint8 CoreId = SpiSlave_GetCoreID();
    struct SpiSlave_Driver_Handler *PerCoreHandler = SpiSlaveHandler[CoreId];
    struct SpiSlave_JobNode *JobNode = PerCoreHandler->JobNode;

    for (uint16 nodeid = 0; nodeid < SPI_SLV_MAX_JOB; nodeid++) {
        JNode = &JobNode[nodeid];
        SPI_SLV_DBG("%d:%d @%p ", JNode->SeqId, JNode->JobId, JNode);

        if (JNode->Node.Next) {
            SPI_SLV_DBG("N-->%p \n", SpiSlaveGetJobNode(JNode->Node.Next));
        } else {
            SPI_SLV_DBG("\n");
        }
    }
}
#endif
#endif
/** **************************************************************************************
 * \brief
 *
 * \verbatim
 * Syntax             : static void SpiSlave_BusPrivInit(uint8 BusIdx)
 *
 * Service ID[hex]    : 0x00
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : configPtr - Pointer to configuration set
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Init The Sequnce Scheduler.
 * \endverbatim
 * Traceability       :
 *****************************************************************************************/
static void SpiSlave_SchedulerInit(void)
{
    SpiSlave_JobType JobId;
    uint8 CoreId = SpiSlave_GetCoreID();
    struct SpiSlave_Driver_Handler *PerCoreHandler = SpiSlaveHandler[CoreId];
#if ((SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_1) || \
     (SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_2))
    struct SpiSlave_SeqNode  *SeqNode = PerCoreHandler->SeqNode;
    struct SpiSlave_JobNode  *JobNode = PerCoreHandler->JobNode;
#endif
#if ((SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_1) || \
     (SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_2) || \
     (SPI_SLV_SUPPORT_CONCURRENT_SYNC_TRANSMIT == STD_ON))
    struct SpiSlave_Scheduler *Sche = &PerCoreHandler->Scheduler;
#endif
    const SpiSlave_JobCfgType *PtrJobCfg = SpiSlave_JobConfig;
    const SpiSlave_SequenceCfgType *PtrSequenceCfg = SpiSlave_SequenceConfig;

    for (SpiSlave_SequenceType i = 0; i < SPI_SLV_TOTAL_SEQ_COUNT; i++) {
        /* */

        JobId = PtrSequenceCfg[i].JobList[0];
#if ((SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_1) || (SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_2))
        JobNode[JobId].Node.Next = NULL_PTR;
        JobNode[JobId].SeqId = i;
        JobNode[JobId].JobId = JobId;
        JobNode[JobId].IsActive = 0;
#endif

#if ((SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_1) || (SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_2))
        SeqNode[i].JobQueue.Next = &JobNode[PtrSequenceCfg[i].JobList[0]].Node;
        SeqNode[i].JobQueue.Prev = NULL;
        SeqNode[i].Node.Next = NULL;
        SeqNode[i].Node.Prev = NULL;
        SeqNode[i].SeqId = i;
        SeqNode[i].CurJob = NULL;
        /* seq priority depends on the highest priority of all jobs*/
        SeqNode[i].Priorty = PtrJobCfg[PtrSequenceCfg[i].JobList[0]].SpiJobPriority;
        SeqNode[i].Interruptable = PtrSequenceCfg[i].InterruptableSequence;
#endif
    }

    /*SyncTransmit parallel */
    PerCoreHandler->SpiSyncSeqActiveCnt = 0;

#if ((SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_1) || (SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_2))

    for (uint8 i = 0; i < SPI_SLV_TOTAL_HW_COUNT; i++) {
        Sche->JobCurr[i] = NULL;
    }

    Sche->State = ASYNC_SLV_SCHE_IDLE;
    Sche->SeqQueue.Next = NULL;
    Sche->SeqQueue.Prev = NULL;
    Sche->HwStatusMask = SpiSlave_InstanceMask_Config[CoreId];
    Sche->PendingSeqCnt = 0;
    Sche->ActiveJobCnt = 0;
#if ( SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_2)
    Sche->SchedulerMode = SPI_SLV_POLLING_MODE;
#elif ( SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_1)
    Sche->SchedulerMode = SPI_SLV_INTERRUPT_MODE;
#endif
#if defined(SPI_SLV_DEBUG_LOG)
    Show_JobNode();
    Show_AllSeqNode();
    Show_scheduler(Sche);
#endif
#elif (SPI_SLV_SUPPORT_CONCURRENT_SYNC_TRANSMIT == STD_ON)
    Sche->HwStatusMask = SpiSlave_InstanceMask_Config[CoreId];
#endif
}
#define SPI_SLV_STOP_SEC_CODE
#include "SpiSlave_MemMap.h"

#define SPI_SLV_START_SEC_CODE_FAST
#include "SpiSlave_MemMap.h"

#if ( SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_1) || ( SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_2)
static void SpiSlave_Sche_Main(void);

#if (SPI_SLV_INTERRUPTIBLE_SEQ_ALLOWED == STD_ON)
/** **************************************************************************************
 * \brief
 *
 * \verbatim
 * Syntax             : static struct SpiSlave_SeqNode *GetInsertSeqNode(
 *                       struct SpiSlave_Scheduler *Sche, struct SpiSlave_SeqNode *New)
 *
 * Service ID[hex]    : 0x00
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : configPtr - Pointer to configuration set
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : get new seq insert point.
 * \endverbatim
 * Traceability       :
 *****************************************************************************************/
static struct SpiSlave_SeqNode *GetInsertSeqNode(struct SpiSlave_Scheduler *Sche, struct SpiSlave_SeqNode *New)
{
    struct SpiSlave_SeqNode *TempSeqNode = NULL_PTR;
    struct SpiSlave_list   *Node = &Sche->SeqQueue;

    while (Node->Next != &Sche->SeqQueue && Node->Next != NULL_PTR) {
        /*PRQA S 2810 2*/
        TempSeqNode = SpiSlaveGetSeqNode(Node->Next);

        if (SpiSlave_SequenceConfig[TempSeqNode->SeqId].SeqHwMask &
            SpiSlave_SequenceConfig[New->SeqId].SeqHwMask) {
            /* The new Seq and the current Seq share the same HwUnit*/
            if (TempSeqNode->Interruptable && TempSeqNode->Priorty < New->Priorty ) {
                /* The current Seq can be interrupted and the priority is lower than the new Seq*/
                return TempSeqNode;
            }
        }

        Node = Node->Next;
    }

    return NULL_PTR;
}
#endif
/** **************************************************************************************
 * \brief
 *
 * \verbatim
 * Syntax             : static Std_ReturnType SpiSlave_ScheOneSequence
 *                       (SpiSlave_SequenceType SequenceId)
 *
 * Service ID[hex]    : 0x00
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : configPtr - Pointer to configuration set
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Service to send the Sequence data.
 * \endverbatim
 * Traceability       :
 *****************************************************************************************/
static Std_ReturnType SpiSlave_ScheOneSequence(SpiSlave_SequenceType SequenceId)
{
    Std_ReturnType ret = E_OK;
#if (SPI_SLV_INTERRUPTIBLE_SEQ_ALLOWED == STD_ON)
    struct SpiSlave_SeqNode *InsertSeqNode;
#endif
    uint8 CoreId = SpiSlave_GetCoreID();
    struct SpiSlave_Driver_Handler *PerCoreHandler = SpiSlaveHandler[CoreId];
    struct SpiSlave_Scheduler *Sche = &PerCoreHandler->Scheduler;
    struct SpiSlave_SeqNode *SeqNode = PerCoreHandler->SeqNode;
    const SpiSlave_SequenceCfgType *PtrSeqConfig = &SpiSlave_SequenceConfig[SequenceId];

    if(TRUE != SpiSlave_ChannelStatusIsOk(SequenceId))
    {
        ret = E_NOT_OK;
    }
    if ((PtrSeqConfig->SeqHwMask & SpiSlave_InstanceMask_Config[CoreId]) != PtrSeqConfig->SeqHwMask) {
        ret = E_NOT_OK;
    }

    if (ret == E_OK) {
        if (0u == Sche->PendingSeqCnt) {
            Sche->SeqQueue.Next = &SeqNode[SequenceId].Node;
            SeqNode[SequenceId].Node.Prev =  &Sche->SeqQueue;
            SeqNode[SequenceId].Node.Next = &Sche->SeqQueue;
            Sche->SeqQueue.Prev = Sche->SeqQueue.Next;
            Sche->PendingSeqCnt++;
        } else {
#if (SPI_SLV_INTERRUPTIBLE_SEQ_ALLOWED == STD_ON)
            /*
                Find the insertion point,if the return is NULL Insert To Tail.
            */
            InsertSeqNode = GetInsertSeqNode(Sche, &SeqNode[SequenceId]);

            if (InsertSeqNode != NULL_PTR) {
                /* interupt curr seq */
                SeqNode[SequenceId].Node.Next = &InsertSeqNode->Node;
                SeqNode[SequenceId].Node.Prev = InsertSeqNode->Node.Prev;
                InsertSeqNode->Node.Prev->Next = &SeqNode[SequenceId].Node;
                InsertSeqNode->Node.Prev = &SeqNode[SequenceId].Node;
                Sche->PendingSeqCnt++;
                SPI_SLV_DBG("Insert Seq %d to Seq prev.\n", SequenceId, InsertSeqNode->SeqId);
            } else {
#endif
                /* add to tail */
                /* SeqQueue.prev point to last Seq queue item */
                /* set the taill seq  next to new seq */
                Sche->SeqQueue.Prev->Next = &SeqNode[SequenceId].Node;
                /* new seq link to old tail */
                SeqNode[SequenceId].Node.Prev = Sche->SeqQueue.Prev;
                /* new seq loop to sche node  */
                SeqNode[SequenceId].Node.Next = &Sche->SeqQueue;
                /* update the tail ptr */
                Sche->SeqQueue.Prev =  &SeqNode[SequenceId].Node;
                /* Tail update to current seq item */
                Sche->PendingSeqCnt++;
                SPI_SLV_DBG("Add Seq %d to queue Tail.\n", SequenceId);
#if (SPI_SLV_INTERRUPTIBLE_SEQ_ALLOWED == STD_ON)
            }

#endif
        }

        SeqNode[SequenceId].SeqInQueue = TRUE;
#if defined(SPI_SLV_DEBUG_LOG)
        Show_scheduler(Sche);
#endif
    }

    return ret;
}
/** **************************************************************************************
 * \brief
 *
 * \verbatim
 * Syntax             : static Std_ReturnType SpiSlave_StartScheJob(
 *                       struct SpiSlave_JobNode *JobNode)
 *
 * Service ID[hex]    : 0x00
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : configPtr - Pointer to configuration set
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Start one job.
 * \endverbatim
 * Traceability       :
 *****************************************************************************************/
static Std_ReturnType SpiSlave_StartScheJob(struct SpiSlave_JobNode *JobNode)
{
    uint32  Length;
    uint16  ChannelId;
    sint32   mld_ret = -1;
    const SpiSlave_DataBufferType *pCurrentTxBuffer;
    SpiSlave_DataBufferType *pCurrentRxBuffer;
    Std_ReturnType ret = E_OK;
    uint8 CoreId = SpiSlave_GetCoreID();
    struct SpiSlave_Driver_Handler *PerCoreHandler = SpiSlaveHandler[CoreId];
    const SpiSlave_JobCfgType *PtrJobCfg = &SpiSlave_JobConfig[JobNode->JobId];
    const SpiSlave_ChannelCfgType *PtrChannelConfig;
    struct mld_spi_slv_module *bus = &PerCoreHandler->SpiBus[PtrJobCfg->HWUnit].Bus;

    /* HwUnitConfigPtr == NULL is not possibility */
    const SpiSlave_HwUnitConfigType *HwUnitConfigPtr =  &SpiSlave_HwUnitConfig[PtrJobCfg->HwUnitIdxCfg];


    ChannelId = PtrJobCfg->ChannelList[0];
    PtrChannelConfig = &(SpiSlave_ChannelConfig[ChannelId]);

    if (PtrChannelConfig->ChannelBufferType == SPI_SLV_IB) {
        pCurrentRxBuffer = (SpiSlave_DataBufferType *)PtrChannelConfig->ReadBufferIndex;
        pCurrentTxBuffer = (SpiSlave_DataBufferType *)PtrChannelConfig->WriteBufferIndex;
        Length = PtrChannelConfig->BufferSize;
    } else {
        pCurrentRxBuffer = (SpiSlave_DataBufferType *)PerCoreHandler->ExtBuff[ChannelId].DesDataBufferPtr;
        pCurrentTxBuffer = (const SpiSlave_DataBufferType *)PerCoreHandler->ExtBuff[ChannelId].SrcDataBufferPtr;
        Length = PerCoreHandler->ExtBuff[ChannelId].Length;
    }

    PerCoreHandler->SpiChannelCB[ChannelId].len = Length;
    PerCoreHandler->SpiChannelCB[ChannelId].ptxdata.val = (uint32)pCurrentTxBuffer;

    if ( PtrChannelConfig->DataWidth < 0x9u )
        PerCoreHandler->SpiChannelCB[ChannelId].width_type = SPI_SLV_DATA_WIDTH_BYTE;
    else if (PtrChannelConfig->DataWidth < 0x11U)
        PerCoreHandler->SpiChannelCB[ChannelId].width_type = SPI_SLV_DATA_WIDTH_HALF_WORD;
    else
        PerCoreHandler->SpiChannelCB[ChannelId].width_type = SPI_SLV_DATA_WIDTH_WORD;

    if (PtrJobCfg->EnableRx == TRUE)
        PerCoreHandler->SpiChannelCB[ChannelId].prxdata.val = (uint32)pCurrentRxBuffer;
    else
        PerCoreHandler->SpiChannelCB[ChannelId].prxdata.val = 0;

    SpiSLvFaultInj_SpiSLv_Dma_Disable();

    /* transmit */
    if (HwUnitConfigPtr->HwDMA == TRUE) {
        mld_ret = mld_spi_slv_vector_transmit_receive_dma(bus, NULL_PTR,
                    &PerCoreHandler->SpiChannelCB[ChannelId]);
        SPI_SLV_DBG("J:%d Job Start to process Slave DMA\n", JobNode->JobId);
    } else {
        mld_ret = mld_spi_slv_vector_transmit_receive_irq(bus, NULL_PTR,
                    &PerCoreHandler->SpiChannelCB[ChannelId]);
        SPI_SLV_DBG("J:%d Job Start to process Slave IRQ\n", JobNode->JobId);
    }

    if (mld_ret < 0) {
        SPI_SLV_DBG("Oops:%s %d %d %d\n", __FUNCTION__, __LINE__, bus->idx, ChannelId);
        ret = E_NOT_OK;
    }

    return ret;
}
#if (SPI_SLV_CANCEL_API == STD_ON)
/**
 * @brief Cancel SPI Slave Sequence.
 *
 * Cancels the specified SPI slave sequence and removes all jobs of that sequence from the queue.
 *
 * @param SeqId Identifier of the SPI slave sequence to cancel.
 */
void SpiSlave_SeqCancel(SpiSlave_SequenceType SeqId)
{
    uint8 HwUnitId;
    uint8 CoreId = SpiSlave_GetCoreID();
    const  SpiSlave_JobCfgType *JobCfg = SpiSlave_JobConfig;
    struct SpiSlave_Driver_Handler *PerCoreHandler = SpiSlaveHandler[CoreId];
    struct SpiSlave_Scheduler *Sche = &PerCoreHandler->Scheduler;
    struct SpiSlave_SeqNode *SeqItem = &PerCoreHandler->SeqNode[SeqId];
    const  SpiSlave_SequenceCfgType *SequenceCfg = SpiSlave_SequenceConfig;

    if (PerCoreHandler->SeqResult[SeqItem->SeqId] == SPI_SLV_SEQ_PENDING) {
        /*
            cancel seq remove all jobs of Seq from queue.
        */
        if (SeqItem->SeqInQueue) {
            SeqItem->Node.Next->Prev = SeqItem->Node.Prev;
            SeqItem->Node.Prev->Next = SeqItem->Node.Next;
            SeqItem->SeqInQueue = FALSE;
            Sche->PendingSeqCnt--;
        }

        if (SeqItem->CurJob && SeqItem->CurJob->IsActive) {
            SeqItem->CurJob->IsActive = 0;
            Sche->ActiveJobCnt--;
            HwUnitId = JobCfg[SeqItem->CurJob->JobId].HWUnit;
            mld_spi_slv_stop(&PerCoreHandler->SpiBus[HwUnitId].Bus);
            Sche->JobCurr[HwUnitId] = NULL_PTR;
            SeqItem->CurJob = NULL_PTR;

            if (0u == Sche->ActiveJobCnt)
                PerCoreHandler->SpiSlave_HandlerAsyncStatus = SPI_SLV_IDLE;
        }

        PerCoreHandler->SeqResult[SeqItem->SeqId] = SPI_SLV_SEQ_CANCELLED;
        /* free controller */
        Sche->HwStatusMask |= SequenceCfg[SeqId].SeqHwMask;
    }
}
#endif
/** **************************************************************************************
 * \brief
 *
 * \verbatim
 * Syntax             : static void SpiSlave_Sche_Main(void)
 *
 * Service ID[hex]    : 0x00
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : configPtr - Pointer to configuration set
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Called When One Job Finish.This function will be called by interrupted and
*                       non-interrupted parts of the code, need to critical section protection
 * \endverbatim
 * Traceability       :
 *****************************************************************************************/
static void SpiSlave_Sche_Main(void)
{
    uint8 HwUnitId;
    struct SpiSlave_SeqNode *SeqItem;
    struct SpiSlave_list  *QueueNode;
    uint8 CoreId = SpiSlave_GetCoreID();
    struct SpiSlave_Driver_Handler *PerCoreHandler = SpiSlaveHandler[CoreId];
    struct SpiSlave_Scheduler *Sche = &PerCoreHandler->Scheduler;
    const SpiSlave_JobCfgType *PtrJobCfg = SpiSlave_JobConfig;

    /* scheduler is ready to  process */
    if (Sche->State  !=  (uint8)ASYNC_SLV_SCHE_UNINIT ) {
        /*
            HwStatusMask may never be 0 in multi-core,at this time, depending on Sche->PendingSeqCnt > 0
            and Next does not point to the queue head, that is, the queue is not empty, the Job under Seq
            will be processed.
            when has unprocessed seq or has Controller is idle or linked list is empty.Some risk points
            here are that when the queue is very large, it will cause the interrupt masking time to be too long.
        */
        SchM_Enter_SpiSlave_SPI_SLV_EXCLUSIVE_AREA_00();
        QueueNode = Sche->SeqQueue.Next;

        while (Sche->PendingSeqCnt && Sche->HwStatusMask &&
               QueueNode != &Sche->SeqQueue && QueueNode) {
            /*PRQA S 2810 2*/
            SeqItem = SpiSlaveGetSeqNode(QueueNode);

            SPI_SLV_DBG("The Seq@%p Id:%d CJ:%p\n", SeqItem, SeqItem->SeqId, SeqItem->CurJob);

            /* seq is not start scheduled */
            if (SeqItem->CurJob == NULL) {
                /* Get first Job to do */
                if (SeqItem->JobQueue.Next) {
                    /*PRQA S 2810 2*/
                    SeqItem->CurJob = SpiSlaveGetJobNode(SeqItem->JobQueue.Next);
                }/* else is not needed */
            } else {
                /* Has been updated by the Job handler to the next Job */
            }

            /*
                if run L:680 the SeqItem->CurJob == NULL
            */
            if (SeqItem->CurJob != NULL_PTR) {
                /* Get Hwidex cached it  */
                HwUnitId = PtrJobCfg[SeqItem->CurJob->JobId].HWUnit;

                /*
                    SeqItem->CurJob->IsActive Job Busy.
                    SpiSlave_GetHWStatus(HwUnitId) Sync HwUint Busy.
                    Sche->HwStatusMask Async HwUnit Busy.
                */
                if ((SeqItem->CurJob->IsActive == FALSE) && \
                    (SpiSlave_GetHWStatus(HwUnitId) == SPI_SLV_IDLE) && \
                    (Sche->HwStatusMask & (((uint32)0x1u) << HwUnitId))) {
                    /*
                        This part of the code needs to be placed here when
                    critical protection is not added. After adding critical protection,
                    it can be moved to the branch of Job OK..
                    */
                    if (SpiSlave_StartScheJob(SeqItem->CurJob) != E_OK) {
                        /*
                            Start Exception;Remove all Seq Jobs from queue
                        */
                        SeqItem->Node.Next->Prev = SeqItem->Node.Prev;
                        SeqItem->Node.Prev->Next = SeqItem->Node.Next;
                        SeqItem->SeqInQueue = FALSE;
                        Sche->PendingSeqCnt--;
                        Sche->JobCurr[HwUnitId] = NULL_PTR;
                        Sche->HwStatusMask |= ((uint32)0x1u) << HwUnitId;
                        SeqItem->CurJob->IsActive = 0u;

                        PerCoreHandler->SeqResult[SeqItem->CurJob->SeqId] = SPI_SLV_SEQ_FAILED;
                        PerCoreHandler->JobResult[SeqItem->CurJob->JobId] = SPI_SLV_JOB_FAILED;

                        SPI_SLV_DBG("S:%d J:%d Job Start Fail\n", SeqItem->CurJob->SeqId, SeqItem->CurJob->JobId);
                        SeqItem->CurJob = NULL_PTR;
                    } else {
                        /* Start Job Pass */
                        Sche->JobCurr[HwUnitId] = SeqItem->CurJob;
                        Sche->HwStatusMask &= (uint32)(~(((uint32)0x1u) << HwUnitId));
                        SeqItem->CurJob->IsActive = 1u;
                        Sche->ActiveJobCnt++;
                        PerCoreHandler->SpiSlave_HandlerAsyncStatus = SPI_SLV_BUSY;
                        PerCoreHandler->JobResult[SeqItem->CurJob->JobId] = SPI_SLV_JOB_PENDING;

                        SPI_SLV_DBG("S:%d J:%d Job Start on SpiSlave_Slave%d\n", SeqItem->CurJob->SeqId, SeqItem->CurJob->JobId,
                                PtrJobCfg[SeqItem->CurJob->JobId].HWUnit + 1u);
                    }
                } else {
                    SPI_SLV_DBG("The SpiSlave_Slave%d is Busy or Job%d is Busy.\n", HwUnitId + 1, SeqItem->CurJob->JobId);
                }
            }
            QueueNode =  QueueNode->Next;
        }

        SchM_Exit_SpiSlave_SPI_SLV_EXCLUSIVE_AREA_00();
    } else {
        SPI_SLV_DBG("Sche is not Inited \n");
    }
}
/** **************************************************************************************
 * \brief
 *
 * \verbatim
 * Syntax             : static void SpiSlave_JobHandleFuntion(uint8 HwUnitId)
 *
 * Service ID[hex]    : 0x00
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : configPtr - Pointer to configuration set
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Called When One Job Finish
 * \endverbatim
 * Traceability       :
 *****************************************************************************************/
static void SpiSlave_JobHandleFuntion(uint8 HwUnitId)
{
    struct SpiSlave_JobNode *JobItem;
    const SpiSlave_JobCfgType *PtrJobCfg;
    boolean need_seq_notification = FALSE;
    uint8 CoreId = SpiSlave_GetCoreID();
    struct SpiSlave_Driver_Handler *PerCoreHandler = SpiSlaveHandler[CoreId];
    struct SpiSlave_Scheduler *Sche = &PerCoreHandler->Scheduler;
    const SpiSlave_SequenceCfgType *Sequence = SpiSlave_SequenceConfig;
    struct SpiSlave_SeqNode  *SeqNode = PerCoreHandler->SeqNode;
    SPI_SLV_DBG("%s SpiSlave_Slave%d \n", __FUNCTION__, HwUnitId + 1);

    SchM_Enter_SpiSlave_SPI_SLV_EXCLUSIVE_AREA_00();

    if (PerCoreHandler->SpiSlave_HandlerAsyncStatus == SPI_SLV_BUSY) {
        /* Job finish */
        JobItem = Sche->JobCurr[HwUnitId];

        if (JobItem) {
            PtrJobCfg = &SpiSlave_JobConfig[JobItem->JobId];

            SPI_SLV_DBG("J @%p S:%d J:%d Job finished.\n", JobItem, JobItem->SeqId, JobItem->JobId);


            /* free controller */
            Sche->HwStatusMask |= (((uint32)0x1) << PtrJobCfg->HWUnit);

            /*
                Except err ,seq end ,or canceled seq.JobItem->Node.Next is const
                do not need critical protection.The large critical section is used
                here to protect when Sche->State = ASYNC_SLV_SCHE_IDLE and then
                SeqNode[JobItem->SeqId].CurJob is updated and JobItem->SeqId is not
                pending, if the asynchronous transfer of JobItem->SeqId is called again ,
                which will affect the enqueuing behavior and introduce uncertainty.
            */
            if (PerCoreHandler->SpiBus[PtrJobCfg->HWUnit].Bus.state & SPI_SLV_STATE_ERR_END) {
                /* Job Failed */
                PerCoreHandler->JobResult[JobItem->JobId] = SPI_SLV_JOB_FAILED;
                PerCoreHandler->SeqResult[JobItem->SeqId] = SPI_SLV_SEQ_FAILED;
                /*PRQA S 2895 1*/
                PerCoreHandler->SpiBus[PtrJobCfg->HWUnit].Bus.state &= (uint32)(~SPI_SLV_STATE_ERR_END);
                need_seq_notification = TRUE;
#if (SPI_SLV_DEV_ERROR_DETECT == STD_ON)
                /* Tx FIFO UDR,RX OVR,DMA Error will report here  */
                Det_ReportRuntimeError(SPI_SLV_MODULE_ID, SPI_SLV_INSTANCE_ID, SPI_SLV_ASYNCTRANSMIT_SID,
                                        SPI_SLV_E_ASYNC_ERROR);
#endif
                SPI_SLV_DBG("J @%p S:%d J:%d Job Fail.\n", JobItem, JobItem->SeqId, JobItem->JobId);
            } else {
                /*
                    Seq Transmit Finished or Canceled by SpiSlave_Cancel Call.
                */
                PerCoreHandler->JobResult[JobItem->JobId] = SPI_SLV_JOB_OK;

                if (JobItem->Node.Next == NULL_PTR) {
                    /*
                        Even though the seq has been canceled, the last Job ended successfully,
                        so this seq is still executed successfully. Any Job fail will set curser status to Fail
                    */
                    if (PerCoreHandler->SeqResult[JobItem->SeqId] == SPI_SLV_SEQ_PENDING ) {
                        PerCoreHandler->SeqResult[JobItem->SeqId] = SPI_SLV_SEQ_OK;
                    }

                    need_seq_notification = TRUE;
                }
            }

            SeqNode[JobItem->SeqId].CurJob = NULL_PTR;

            if (SeqNode[JobItem->SeqId].SeqInQueue) {
                SeqNode[JobItem->SeqId].Node.Next->Prev = SeqNode[JobItem->SeqId].Node.Prev;
                SeqNode[JobItem->SeqId].Node.Prev->Next = SeqNode[JobItem->SeqId].Node.Next;
                SeqNode[JobItem->SeqId].SeqInQueue = FALSE;
                Sche->PendingSeqCnt--;
            }

            SPI_SLV_DBG("S:%d Seq End.\n", JobItem->SeqId);
            /*
                Note:Update the state machine before Notifaction to avoid exceptions
                when calling asynchronous transfers in Notifaction.
            */
            Sche->ActiveJobCnt--;
            /* finish curr job */
            JobItem->IsActive = 0u;
            /* avoid polling mode Notification multi called */
            Sche->JobCurr[HwUnitId] = NULL_PTR;
            /* Notification cannot be called in critical section */

            /*
                Here Sche->PendingSeqCnt may be 0, if (Sche->PendingSeqCnt)
                should be placed after Notifaction to support starting a new
                asynchronous transfer in Notifaction.
            */
            if (PtrJobCfg->JobEndNotification) {
                PtrJobCfg->JobEndNotification();
                SPI_SLV_DBG("S:%d J:%d Job Finish Notification.\n", JobItem->SeqId, JobItem->JobId);
            }

            if (need_seq_notification && Sequence[JobItem->SeqId].SequenceEndNotification) {
                Sequence[JobItem->SeqId].SequenceEndNotification();
                SPI_SLV_DBG("S:%d Seq Finish Notification.\n", JobItem->SeqId);
            }

            /* Have seq need sche */
            if (Sche->PendingSeqCnt) {
                SpiSlave_Sche_Main();
            } else {
                /*
                    HwStatusMask will modify by Synctransmit so Sche->HwStatusMask != HW_ALL_FREE_MASK
                    Asyntransfers may also be idle .
                */
            }

            if (0u == Sche->ActiveJobCnt) {
                PerCoreHandler->SpiSlave_HandlerAsyncStatus = SPI_SLV_IDLE;
            }
        } else {
            /* Poling mode this case will happen */
        }
    } else {
        SPI_SLV_DBG("AS:%d SS:%d\n", PerCoreHandler->SpiSlave_HandlerAsyncStatus, PerCoreHandler->SpiSlave_HandlerStatus);
    }

    SchM_Exit_SpiSlave_SPI_SLV_EXCLUSIVE_AREA_00();
}
#endif
#define SPI_SLV_STOP_SEC_CODE_FAST
#include "SpiSlave_MemMap.h"

#define SPI_SLV_START_SEC_CODE
#include "SpiSlave_MemMap.h"
/*******************************************************************************
**                      Function Definitions                                  **
*******************************************************************************/
 /** ***************************************************************************
 * \brief
 *
 * \verbatim
 * Syntax             : void SpiSlave_InitData(VAR(void, AUTOMATIC))
 *
 * Service ID[hex]    : 0x00
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : configPtr - Pointer to configuration set
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : SpiSlave_InitData.
 * \endverbatim
 * Traceability       :
 ******************************************************************************/
FUNC(void, SPI_SLV_CODE)
SpiSlave_InitData(VAR(void, AUTOMATIC))
{
    uint8 CoreId = SpiSlave_GetCoreID();
    const SpiSlave_JobCfgType *PtrJobCfg = SpiSlave_JobConfig;
    struct SpiSlave_Driver_Handler *PerCoreHandler = SpiSlaveHandler[CoreId];

    /* Initialise  Every Hw bus Unit  Private data*/
    for (uint8 hwid = 0; hwid < SPI_SLV_TOTAL_HW_COUNT; hwid++) {
        SpiSlave_BusPrivInit(hwid);
    }

    /* Initialise  Every Device  Private data */
    for (SpiSlave_JobType JobIdx = 0; JobIdx < SPI_SLV_TOTAL_JOB_COUNT; JobIdx++) {
        SpiSlave_DevicePrivInit(PtrJobCfg[JobIdx].DeviceIdx, &PtrJobCfg[JobIdx]);
    }

    /* Initialise Job result Array */
    for (SpiSlave_JobType JobIdx = 0; JobIdx < SPI_SLV_TOTAL_JOB_COUNT; JobIdx++) {
        PerCoreHandler->JobResult[JobIdx] = SPI_SLV_JOB_OK;
    }

    for (SpiSlave_SequenceType i = 0; i < SPI_SLV_TOTAL_SEQ_COUNT; i++) {
        /* Initialise Sequence result Array */
        PerCoreHandler->SeqResult[i] = SPI_SLV_SEQ_OK;
#if SPI_SLV_CANCEL_API == STD_ON
        PerCoreHandler->SeqCancel[i] = FALSE;
#endif
    }
    for (SpiSlave_ChannelType chanIdx = 0; chanIdx < SPI_SLV_MAX_CHANNEL; chanIdx++) {
        PerCoreHandler->SpiSlave_SpiChannelState[chanIdx].BuffLock = B_SLV_UNLOCK;
        PerCoreHandler->SpiSlave_SpiChannelState[chanIdx].BuffSta = B_SLV_NO_SETED;
    }
    /* Init Scheduer Dependent Parameter*/
    SpiSlave_SchedulerInit();
}
#if (SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_2)
/** **************************************************************************************
 * \brief
 *
 * \verbatim
 * Syntax             : void SpiSlave_AsyncModeSet(SpiSlave_AsyncModeType mode)
 *
 * Service ID[hex]    : 0x00
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : configPtr - Pointer to configuration set
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Setup SpiSlave_Slave Async mode.
 * \endverbatim
 * Traceability       :
 *****************************************************************************************/
void SpiSlave_AsyncModeSet(SpiSlave_AsyncModeType mode)
{
    uint8 CoreId = SpiSlave_GetCoreID();
    struct SpiSlave_Driver_Handler *PerCoreHandler = SpiSlaveHandler[CoreId];
    struct SpiSlave_Scheduler *Sche = &PerCoreHandler->Scheduler;

    for (uint8 HwIdx = 0; HwIdx < SPI_SLV_TOTAL_HW_COUNT; HwIdx++) {
        if (SpiSlave_InstanceMask_Config[CoreId] & (((uint32)0x1) << HwIdx)) {
            if (SPI_SLV_POLLING_MODE == mode) {
                /*PRQA S 2895 1*/
                PerCoreHandler->SpiBus[HwIdx].Bus_Priv.flags &= (uint32)(~(SPI_SLAVE_INTERRUPT_MODE));
            } else {
                PerCoreHandler->SpiBus[HwIdx].Bus_Priv.flags |= SPI_SLAVE_INTERRUPT_MODE;
            }
        }
    }

    Sche->SchedulerMode = mode;
}
#endif
/** ***************************************************************************
 * \brief
 *
 * \verbatim
 * Syntax             : void SpiSlave_HWInit(void)
 *
 * Service ID[hex]    : 0x00
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : configPtr - Pointer to configuration set
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : This service initializes the HW Unit.
 * \endverbatim
 * Traceability       :
 ******************************************************************************/
FUNC(Std_ReturnType, SPI_SLV_CODE)
SpiSlave_HWInit(void)
{
    uint8 DevPrivIdx;
    uint8 HwUnit, DeviceIdx, CoreId = SpiSlave_GetCoreID();
    const SpiSlave_JobCfgType *PtrJobCfg = SpiSlave_JobConfig;
    struct SpiSlave_Driver_Handler *PerCoreHandler = SpiSlaveHandler[CoreId];
    const SpiSlave_HwUnitConfigType *  ctrlCfgs;
    /* initialize HW units */
    for (uint8 HwIdx = 0; HwIdx < SPI_SLV_TOTAL_HW_COUNT; HwIdx++)
    {
        ctrlCfgs = Get_JobHwUnitConfig(HwIdx);

        if(NULL_PTR != ctrlCfgs)
        {
            mld_spi_slv_bus_create(&PerCoreHandler->SpiBus[HwIdx].Bus, \
                            ctrlCfgs->ctrlRegBase, \
                            &semidrive_spi_slv_bus_ops);
            /*
                pre-spi controller only map to one extenal device
                so the first job device configuration can used.
            */
            DevPrivIdx = Get_SlaveModeConfigDeviceIdx(HwIdx);
            /* config params attach */
            mld_spi_slv_bus_set_privdata(&PerCoreHandler->SpiBus[HwIdx].Bus, \
                                        &PerCoreHandler->SpiBus[HwIdx].Bus_Priv, \
                                        &PerCoreHandler->SpiDevice[DevPrivIdx].Device_Priv);
            SPI_SLV_DBG("The Bus %d is Slave.\n", HwIdx);

            PerCoreHandler->SpiBus[HwIdx].Bus.idx = HwIdx;

            /* Not alloc this controller */
            if (SpiSlave_InstanceMask_Config[CoreId] & (((uint32)0x1u) << HwIdx)) {
                if (mld_spi_slv_init(&PerCoreHandler->SpiBus[HwIdx].Bus) < 0)
                    return E_NOT_OK;
            }
        }
    }

    for (uint8 DevIdx = 0; DevIdx < SPI_SLV_TOTAL_DEV_COUNT; DevIdx++)
    {
        PerCoreHandler->SpiDevice[DevIdx].Device.priv = NULL_PTR;
        PerCoreHandler->SpiDevice[DevIdx].Device.bus = NULL_PTR;
    }

    /* Initialize and add Job to HW units*/
    for (uint8 JobIdx = 0; JobIdx < SPI_SLV_TOTAL_JOB_COUNT; JobIdx++)
    {
        /* spi HW units init */
        HwUnit = PtrJobCfg[JobIdx].HWUnit;
        DeviceIdx = PtrJobCfg[JobIdx].DeviceIdx;

        /* spi device init */
        mld_spi_slv_dev_init(&PerCoreHandler->SpiDevice[DeviceIdx].Device, \
                         &PerCoreHandler->SpiDevice[DeviceIdx].Device_Priv);
        /*
            spi device attach spi ,There will set the cs polarity;
            the upper layer should prevent that different devices
            on the same bus use the same cs signal.
            soft cs do not need touch hw cs config bits.
        */
        if (SpiSlave_InstanceMask_Config[CoreId] & (((uint32)0x1) << HwUnit)) {
            mld_spi_slv_dev_attach_bus(&PerCoreHandler->SpiDevice[DeviceIdx].Device, \
                &PerCoreHandler->SpiBus[HwUnit].Bus);
        }
    }

    return E_OK;
}
/** ***************************************************************************
 * \brief
 *
 * \verbatim
 * Syntax             : void SpiSlave_HWDeInit(void)
 *
 * Service ID[hex]    : 0x00
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : configPtr - Pointer to configuration set
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : This service SpiSlave_HWDeInit.
 * \endverbatim
 * Traceability       :
 ******************************************************************************/
FUNC(Std_ReturnType, SPI_SLV_CODE)
SpiSlave_HWDeInit(void)
{
    uint8 CoreId = SpiSlave_GetCoreID();
    struct SpiSlave_Driver_Handler *PerCoreHandler = SpiSlaveHandler[CoreId];

    for (uint8 BusIdx = 0; BusIdx < SPI_SLV_TOTAL_HW_COUNT; BusIdx++) {
        if (SpiSlave_InstanceMask_Config[CoreId] & (((uint32)0x1) << BusIdx))
            mld_spi_slv_deinit(&PerCoreHandler->SpiBus[BusIdx].Bus);
    }

    return E_OK;
}
/** ***************************************************************************
 * \brief
 *
 * \verbatim
 * Syntax             : void SpiSlave_JobSyncTransmit(void)
 *
 * Service ID[hex]    : 0x00
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : LddJobIndex - Index of the Job in Job config Array
 * Parameters (in)    : LddSequence - Sequence Index ID
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : This service SpiSlave_JobSyncTransmit.
 * \endverbatim
 * Traceability       :
 ******************************************************************************/
#if ((SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_0) || (SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_2))
static FUNC(Std_ReturnType, SPI_SLV_CODE) SpiSlave_JobSyncTransmit(SpiSlave_JobType JobId,
        const SpiSlave_JobCfgType *PtrJobConfig)
{
    sint32 ret = -1;
    uint16  Length;
    uint16  ChannelId;
    uint8 CoreId = SpiSlave_GetCoreID();
    Std_ReturnType ReturnValue = E_OK;
    struct mld_spi_slv_module *bus;
    const SpiSlave_DataBufferType *pCurrentTxBuffer;
    SpiSlave_DataBufferType *pCurrentRxBuffer;
    const SpiSlave_ChannelCfgType *PtrChannelConfig;
    struct SpiSlave_Driver_Handler *PerCoreHandler = SpiSlaveHandler[CoreId];

    /* Set the Job status result */
    PerCoreHandler->JobResult[JobId] = SPI_SLV_JOB_PENDING;

    ChannelId = PtrJobConfig->ChannelList[0];
    PtrChannelConfig = &(SpiSlave_ChannelConfig[ChannelId]);

    if (PtrChannelConfig->ChannelBufferType == SPI_SLV_IB) {
        pCurrentRxBuffer = (SpiSlave_DataBufferType *)PtrChannelConfig->ReadBufferIndex;
        pCurrentTxBuffer = (SpiSlave_DataBufferType *)PtrChannelConfig->WriteBufferIndex;
        Length = (uint16)PtrChannelConfig->BufferSize;
    } else {
        pCurrentRxBuffer = (SpiSlave_DataBufferType *)PerCoreHandler->ExtBuff[\
                            ChannelId].DesDataBufferPtr;

        pCurrentTxBuffer = (const SpiSlave_DataBufferType *)PerCoreHandler->ExtBuff[\
                            ChannelId].SrcDataBufferPtr;
        Length = PerCoreHandler->ExtBuff[PtrJobConfig->ChannelList[0]].Length;
    }

    PerCoreHandler->SpiChannelCB[ChannelId].len = Length;
    PerCoreHandler->SpiChannelCB[ChannelId].ptxdata.val = (uint32)pCurrentTxBuffer;

    if ( PtrChannelConfig->DataWidth < 0x9u )
        PerCoreHandler->SpiChannelCB[ChannelId].width_type = SPI_SLV_DATA_WIDTH_BYTE;
    else if (PtrChannelConfig->DataWidth < 0x11U)
        PerCoreHandler->SpiChannelCB[ChannelId].width_type = SPI_SLV_DATA_WIDTH_HALF_WORD;
    else
        PerCoreHandler->SpiChannelCB[ChannelId].width_type = SPI_SLV_DATA_WIDTH_WORD;

    if (PtrJobConfig->EnableRx == TRUE)
        PerCoreHandler->SpiChannelCB[ChannelId].prxdata.val = (uint32)pCurrentRxBuffer;
    else
        PerCoreHandler->SpiChannelCB[ChannelId].prxdata.val = 0;

    bus = &PerCoreHandler->SpiBus[PtrJobConfig->HWUnit].Bus;

    ret = mld_spi_slv_vector_transmit_receive(bus, NULL_PTR, &PerCoreHandler->SpiChannelCB[ChannelId]);

    if (ret < 0) {
        ReturnValue = E_NOT_OK;
    }
    /* Set the Job status result */
    if (ReturnValue == E_OK) {
        PerCoreHandler->JobResult[JobId] = SPI_SLV_JOB_OK;
    } else {
        PerCoreHandler->JobResult[JobId] = SPI_SLV_JOB_FAILED;
    }

    if (PtrJobConfig->JobEndNotification) {
        PtrJobConfig->JobEndNotification();
    }


    return ReturnValue;
}
#endif
/** ***************************************************************************
 * \brief
 *
 * \verbatim
 * Syntax             : void SpiSlave_SeqSyncTransmit(void)
 *
 * Service ID[hex]    : 0x00
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : SequenceId - Index of the Job in Job config Array
 * Parameters (in)    : PtrSeqConfig - Sequence Index ID
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : This service SpiSlave_SeqSyncTransmit.
 * \endverbatim
 * Traceability       :
 ******************************************************************************/
#if ((SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_0) || (SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_2))
FUNC(Std_ReturnType, SPI_SLV_CODE)
SpiSlave_SeqSyncTransmit(SpiSlave_SequenceType SequenceId, const SpiSlave_SequenceCfgType *PtrSeqConfig)
{
    Std_ReturnType ReturnValue = E_OK;
    uint8 CoreId = SpiSlave_GetCoreID();
    struct SpiSlave_Driver_Handler *PerCoreHandler = SpiSlaveHandler[CoreId];
    if(TRUE != SpiSlave_ChannelStatusIsOk(SequenceId))
    {
        ReturnValue = E_NOT_OK;
    }
    else
    {
        /* Change sequence status to Pending */
        PerCoreHandler->SeqResult[SequenceId] = SPI_SLV_SEQ_PENDING;

        ReturnValue = SpiSlave_JobSyncTransmit(PtrSeqConfig->JobList[0],\
                    &SpiSlave_JobConfig[PtrSeqConfig->JobList[0]]);

        if (E_OK == ReturnValue){
            /* Change sequence status to OK */
            PerCoreHandler->SeqResult[SequenceId] = SPI_SLV_SEQ_OK;
        }else{
            PerCoreHandler->SeqResult[SequenceId] = SPI_SLV_SEQ_FAILED;
        }
        if (PtrSeqConfig->SequenceEndNotification)
            PtrSeqConfig->SequenceEndNotification();
    }
    return ReturnValue;
}
#endif
/** ***************************************************************************
 * \brief
 *
 * \verbatim
 * Syntax             : SpiSlave_StatusType SpiSlave_GetHWStatus(SpiSlave_HWUnitType HwUnit)
 *
 * Service ID[hex]    : 0x00
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : SequenceId - Index of the Job in Job config Array
 * Parameters (in)    : PtrSeqConfig - Sequence Index ID
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : This function reads the HW status from  DW_SSI_SR register.
 * \endverbatim
 * Traceability       :
 ******************************************************************************/
FUNC(SpiSlave_StatusType, SPI_SLV_CODE) SpiSlave_GetHWStatus(SpiSlave_HWUnitType HwUnit)
{
    SpiSlave_StatusType ret;
    uint8 CoreId = SpiSlave_GetCoreID();
    struct SpiSlave_Driver_Handler *PerCoreHandler = SpiSlaveHandler[CoreId];
    struct mld_spi_slv_module *bus = &PerCoreHandler->SpiBus[HwUnit].Bus;

    if (!(bus->state & SPI_SLV_STATE_INITED))
        ret = SPI_SLV_UNINIT;
    else if (bus->state & SPI_SLV_BUS_BUSY_MASK)
        ret = SPI_SLV_BUSY;
    else
        ret = SPI_SLV_IDLE;

    return ret;
}
/*********************************************************************************
* Functions
**********************************************************************************/
#define SPI_SLV_STOP_SEC_CODE
#include "SpiSlave_MemMap.h"

#define SPI_SLV_START_SEC_CODE_FAST
#include "SpiSlave_MemMap.h"
/**************************************************************************************************
*  Service name        : SpiSlave_HwAsyncTransmit
*
*  Syntax              : Std_ReturnType SpiSlave_HwAsyncTransmit( SpiSlave_SequenceType Sequence )
*
*  Parameters (in)     : Sequence - Sequence ID.
*
*  Parameters (in-out) : None
*
*  Parameters (out)    : None
*
*  Return value        : E_OK: Transmission command has been accepted
                         E_NOT_OK: Transmission command has not been accepted
*
*  Description         : Service to transmit data on the SPI bus.
*****************************************************************************************************/
#if (SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_1) || (SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_2)
Std_ReturnType SpiSlave_HwAsyncTransmit(SpiSlave_SequenceType Sequence)
{
    uint8 CoreId = SpiSlave_GetCoreID();
    Std_ReturnType ReturnValue = E_OK;
    struct SpiSlave_Driver_Handler *PerCoreHandler = SpiSlaveHandler[CoreId];
    struct SpiSlave_Scheduler *Sche = &PerCoreHandler->Scheduler;
    const SpiSlave_SequenceCfgType *SeqConfigPtr = &SpiSlave_SequenceConfig[Sequence];
    SPI_SLV_DBG("%s call param %d \n", __FUNCTION__, Sequence);

    /* Async scheduler not init */
    if (Sche->State == (uint8)ASYNC_SLV_SCHE_UNINIT) {
        /*  error handle */
        ReturnValue =  E_NOT_OK;
    } else {
        SchM_Enter_SpiSlave_SPI_SLV_EXCLUSIVE_AREA_014();

        /* Check whether the sequence is already running or not */
        if (PerCoreHandler->SeqResult[Sequence] == SPI_SLV_SEQ_PENDING) {
#if (SPI_SLV_DEV_ERROR_DETECT == STD_ON)
            Det_ReportRuntimeError(SPI_SLV_MODULE_ID, SPI_SLV_INSTANCE_ID, SPI_SLV_ASYNCTRANSMIT_SID,
                                   SPI_SLV_E_SEQ_PENDING);
#endif
            /* busy seq */
            ReturnValue =  E_NOT_OK;
        } else {
            /* enqueue to queue */
            if (SpiSlave_ScheOneSequence(Sequence) != E_OK) {
                ReturnValue =  E_NOT_OK;
            } else {
                /* [SWS_SpiSlave_00020] The function SpiSlave_AsyncTransmit shall take over the given parameter,
                    initiate a transmission,set the sequence result to SPI_SLV_SEQ_PENDING */
                PerCoreHandler->SeqResult[Sequence] = SPI_SLV_SEQ_PENDING;
#if SPI_SLV_CANCEL_API == STD_ON
                /* Clear last dummy cancel flags */
                PerCoreHandler->SeqCancel[Sequence] = FALSE;
#endif
                /* [SWS_SpiSlave_00194]When the function SpiSlave_AsyncTransmit is called,
                    shall take over the given parameter and set the Job status to SPI_SLV_JOB_QUEUED,*/
                PerCoreHandler->JobResult[SeqConfigPtr->JobList[0]] = SPI_SLV_JOB_QUEUED;
                /*  trigger schedule running */
                SpiSlave_Sche_Main();
            }
        }

        SchM_Exit_SpiSlave_SPI_SLV_EXCLUSIVE_AREA_014();
    }

    return ReturnValue;
}
#endif

/**********************************************************************************
*  Service name        : SpiSlave_HwMainFunctionHandling
*
*  Syntax              : Std_ReturnType SpiSlave_HwMainFunctionHandling( SpiSlave_JobType Job )
*
*  Parameters (in)     : Job - Job ID.
*
*  Description         : This service Specifies the last transmission request of the Job.
***********************************************************************************/
FUNC(void, SPI_SLV_CODE) SpiSlave_HwMainFunctionHandling(uint8 Hwidx)
{
#if ( SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_1) || ( SPI_SLV_LEVEL_DELIVERED == SPI_SLV_LEVEL_2)
    uint8 CoreId = SpiSlave_GetCoreID();

    struct SpiSlave_Driver_Handler *PerCoreHandler = SpiSlaveHandler[CoreId];
    sint32 ret = mld_spi_slv_async_polling(&PerCoreHandler->SpiBus[Hwidx].Bus);

    if (!ret)
        /* transmit finished */
        SpiSlave_JobHandleFuntion(Hwidx);

#endif
} /* end of SpiSlave_HwMainFunctionHandling */

#if (SPI_SLV_DEV_ERROR_DETECT == STD_ON)
/**
 * @brief Get Core ID Assigned to SPI Slave Channel
 *
 * Retrieve the core ID assigned to a given SPI slave channel type.
 *
 * @param Channel Type of the SPI slave channel
 *
 * @return The assigned core ID
 */
uint32 SpiSlave_GetChannelAssignCoreId(SpiSlave_ChannelType Channel)
{
    /*Default assign to sf core */
    uint32 CoreId = 0u;

    for (uint16 JobIdx = 0u; JobIdx < SPI_SLV_TOTAL_JOB_COUNT; JobIdx++) {
        if (SpiSlave_JobConfig[JobIdx].ChannelList[0] == Channel) {
            for (uint8 Core = 0u; Core < SPI_SLV_MAX_CORES; Core++) {
                if (SpiSlave_InstanceMask_Config[Core] & (((uint32)0x1) << SpiSlave_JobConfig[JobIdx].HWUnit)) {
                    CoreId = Core;
                    return CoreId;
                }
            }
        }
    }
    return CoreId;
}

/**
 * @brief Get Core ID Assigned to SPI Slave Task
 *
 * Retrieve the core ID assigned to a specified SPI slave task type.
 *
 * @param JobId Type of the SPI slave task
 *
 * @return The assigned core ID
 */

uint32 SpiSlave_GetJobAssignCoreId(SpiSlave_JobType JobId)
{
    /*Default assign to sf core */
    uint32 CoreId = 0;

    if(SPI_SLV_MAX_JOB <= JobId){
      CoreId = SPI_SLV_MAX_CORES;
    }
    else
    {
      for (uint8 Core = 0; Core < SPI_SLV_MAX_CORES; Core++) {
          if (SpiSlave_InstanceMask_Config[Core] & (((uint32)0x1) << SpiSlave_JobConfig[JobId].HWUnit)) {
              CoreId = Core;
              break;
          }
      }
    }

    return CoreId;
}

/**
 * @brief Get Core ID Assigned to SPI Slave Sequence
 *
 * Retrieve the core ID assigned to a given SPI slave sequence type.
 *
 * @param Sequence Type of the SPI slave sequence
 *
 * @return The assigned core ID
 */
uint32 SpiSlave_GetSequenceAssignCoreId(SpiSlave_SequenceType Sequence)
{
    return SpiSlave_GetJobAssignCoreId(SpiSlave_SequenceConfig[Sequence].JobList[0]);
}
#endif

#define SPI_SLV_STOP_SEC_CODE_FAST
#include "SpiSlave_MemMap.h"

#ifdef __cplusplus
}
#endif
